# -*- coding: utf-8 -*-
"""
Tencent is pleased to support the open source community by making 蓝鲸智云PaaS平台社区版 (BlueKing PaaS Community
Edition) available.
Copyright (C) 2017-2021 THL A29 Limited, a Tencent company. All rights reserved.
Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://opensource.org/licenses/MIT
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.
"""

import json
from django.test import TestCase, Client
from django.urls import reverse
from django.contrib.auth import get_user_model
from unittest.mock import patch, MagicMock
from home_application.models import (
    Business, Set, Module, Host, HostDetail, 
    BackupRecord, ApiRequestCount
)
from home_application.constants import (
    MAX_ATTEMPTS, JOB_RESULT_ATTEMPTS_INTERVAL, JOB_BK_BIZ_ID, BK_JOB_HOST,
    WAITING_CODE, SUCCESS_CODE, WEB_SUCCESS_CODE, SEARCH_FILE_PLAN_ID,
    BACKUP_FILE_PLAN_ID
)


class BaseTestCase(TestCase):
    """基础测试类，提供通用的测试数据和方法"""
    
    def setUp(self):
        self.client = Client()
        self.user = get_user_model().objects.create_user(
            username='testuser',
            password='testpass123',
            is_staff=True,
            is_active=True
        )
        self.client.force_login(self.user)
        
        # 创建测试数据
        self.business = Business.objects.create(
            bk_biz_id=1,
            bk_biz_name="测试业务"
        )
        
        self.set = Set.objects.create(
            bk_set_id=1,
            bk_set_name="测试集群",
            bk_biz_id=self.business
        )
        
        self.module = Module.objects.create(
            bk_module_id=1,
            bk_module_name="测试模块",
            bk_set_id=self.set,
            bk_biz_id=self.business
        )
        
        self.host = Host.objects.create(
            bk_host_id=1,
            bk_cloud_id=0,
            bk_host_innerip="127.0.0.1",
            bk_os_type="Linux",
            bk_mac="00:00:00:00:00:01",
            operator="admin",
            bk_bak_operator="backup",
            bk_biz_id=self.business,
            bk_set_id=self.set,
            bk_module_id=self.module
        )
        
        self.host_detail = HostDetail.objects.create(
            host=self.host,
            cpu="Intel(R) Core(TM) i7-8700K",
            memory="16GB",
            disk="500GB SSD",
            os_version="CentOS 7.6"
        )
        
        self.backup_record = BackupRecord.objects.create(
            bk_host_id=1,
            bk_file_dir="/var/log",
            bk_file_suffix=".log",
            bk_backup_name="test_backup_20231201.log",
            bk_file_create_time="2023-12-01 10:00:00",
            bk_file_operator="admin",
            bk_job_link="http://job.example.com/task/123"
        )
        
        self.api_request_count = ApiRequestCount.objects.create(
            api_category="host",
            api_name="get_hosts_list",
            request_count=10
        )


class HostListApiTest(BaseTestCase):
    """主机列表API测试"""

    def test_host_list_pagination(self):
        """测试主机列表分页功能"""
        response = self.client.get('/host-list', {
            'bk_biz_id': 1,
            'page': 1,
            'page_size': 5
        })
        self.assertEqual(response.status_code, 200)
        data = response.json()
        self.assertIn('data', data)
        self.assertIn('info', data['data'])
        self.assertIn('count', data['data'])

    @patch("home_application.views.get_client_by_request")
    def test_host_list_success(self, mock_get_client):
        """测试主机列表查询成功"""
        mock_client = MagicMock()
        mock_client.cc.list_biz_hosts.return_value = {
            "result": True,
            "data": {
                "info": [
                    {
                        "bk_host_id": 1,
                        "bk_host_innerip": "127.0.0.1",
                        "operator": "admin",
                        "bk_bak_operator": "backup"
                    }
                ],
                "count": 1
            }
        }
        mock_get_client.return_value = mock_client
        
        response = self.client.get("/host-list", {
            "bk_biz_id": 1,
            "page": 1,
            "page_size": 10
        })
        
        self.assertEqual(response.status_code, 200)
        data = response.json()
        self.assertEqual(data["code"], 0)
        self.assertEqual(data["data"]["count"], 1)
        self.assertEqual(len(data["data"]["info"]), 1)

    @patch("home_application.views.get_client_by_request")
    def test_host_list_fail(self, mock_get_client):
        """测试主机列表查询失败"""
        mock_client = MagicMock()
        mock_client.cc.list_biz_hosts.return_value = {
            "result": False,
            "message": "mock error"
        }
        mock_get_client.return_value = mock_client
        
        response = self.client.get("/host-list", {
            "bk_biz_id": 1,
            "page": 1,
            "page_size": 10
        })
        
        self.assertEqual(response.status_code, 200)
        data = response.json()
        self.assertEqual(data["code"], 1)
        self.assertEqual(data["data"]["count"], 0)

    def test_host_list_invalid_pagination(self):
        """测试主机列表分页参数无效"""
        response = self.client.get("/host-list", {
            "bk_biz_id": 1,
            "page": "invalid",
            "page_size": "invalid"
        })
        
        self.assertEqual(response.status_code, 200)
        data = response.json()
        self.assertEqual(data["code"], 0)  # 应该使用默认值

    @patch("home_application.views.get_client_by_request")
    def test_host_list_with_filters(self, mock_get_client):
        """测试主机列表带过滤条件"""
        mock_client = MagicMock()
        mock_client.cc.list_biz_hosts.return_value = {
            "result": True,
            "data": {"info": [], "count": 0}
        }
        mock_get_client.return_value = mock_client
        
        response = self.client.get("/host-list", {
            "bk_biz_id": 1,
            "bk_set_id": 1,
            "bk_module_id": 1,
            "operator": "admin"
        })
        
        self.assertEqual(response.status_code, 200)
        # 验证调用参数包含过滤条件
        mock_client.cc.list_biz_hosts.assert_called_once()


class LogSearchApiTest(BaseTestCase):
    """日志查询API测试"""

    @patch("home_application.views.get_client_by_request")
    def test_search_file_success(self, mock_get_client):
        """测试文件搜索成功"""
        mock_client = MagicMock()
        # 模拟作业执行成功
        mock_client.jobv3.execute_job_plan.return_value = {
            "data": {"job_instance_id": 12345}
        }
        mock_client.jobv3.get_job_instance_status.return_value = {
            "data": {
                "step_instance_list": [{"status": SUCCESS_CODE, "step_instance_id": 67890}]
            }
        }
        mock_client.jobv3.get_job_instance_ip_log.return_value = {
            "data": {
                "bk_host_id": 1,
                "log_content": json.dumps([{
                    "file_path": "/var/log/test.log",
                    "file_size": "1024",
                    "file_time": "2023-12-01 10:00:00"
                }])
            }
        }
        mock_get_client.return_value = mock_client
        
        response = self.client.get("/search-file", {
            "host_id_list": "1",
            "search_path": "/var/log",
            "suffix": ".log"
        })
        
        self.assertEqual(response.status_code, 200)
        data = response.json()
        self.assertTrue(data["result"])
        self.assertEqual(data["code"], WEB_SUCCESS_CODE)

    @patch("home_application.views.get_client_by_request")
    def test_search_file_job_failed(self, mock_get_client):
        """测试文件搜索作业执行失败"""
        mock_client = MagicMock()
        mock_client.jobv3.execute_job_plan.return_value = {
            "data": {"job_instance_id": 12345}
        }
        mock_client.jobv3.get_job_instance_status.return_value = {
            "data": {
                "step_instance_list": [{"status": 3}]  # 失败状态
            }
        }
        mock_get_client.return_value = mock_client
        
        response = self.client.get("/search-file", {
            "host_id_list": "1",
            "search_path": "/var/log",
            "suffix": ".log"
        })
        
        self.assertEqual(response.status_code, 200)
        data = response.json()
        self.assertFalse(data["result"])
        self.assertEqual(data["message"], "search failed")

    @patch("home_application.views.get_client_by_request")
    def test_search_file_timeout(self, mock_get_client):
        """测试文件搜索超时"""
        mock_client = MagicMock()
        mock_client.jobv3.execute_job_plan.return_value = {
            "data": {"job_instance_id": 12345}
        }
        # 模拟一直等待状态
        mock_client.jobv3.get_job_instance_status.return_value = {
            "data": {
                "step_instance_list": [{"status": WAITING_CODE}]
            }
        }
        mock_get_client.return_value = mock_client
        
        response = self.client.get("/search-file", {
            "host_id_list": "1",
            "search_path": "/var/log",
            "suffix": ".log"
        })
        
        self.assertEqual(response.status_code, 200)
        data = response.json()
        self.assertFalse(data["result"])

    def test_search_file_invalid_params(self):
        """测试文件搜索参数无效"""
        response = self.client.get("/search-file", {
            "host_id_list": "",
            "search_path": "",
            "suffix": ""
        })
        
        self.assertEqual(response.status_code, 200)
        # 应该返回错误信息


class LogBackupApiTest(BaseTestCase):
    """日志备份API测试"""

    @patch("home_application.views.get_client_by_request")
    def test_backup_file_success(self, mock_get_client):
        """测试文件备份成功"""
        mock_client = MagicMock()
        mock_client.jobv3.execute_job_plan.return_value = {
            "data": {"job_instance_id": 12345}
        }
        mock_client.jobv3.get_job_instance_status.return_value = {
            "data": {
                "step_instance_list": [{"status": SUCCESS_CODE, "step_instance_id": 67890}]
            }
        }
        mock_client.jobv3.get_job_instance_ip_log.return_value = {
            "data": {
                "bk_host_id": 1,
                "log_content": json.dumps([{
                    "file_path": "/var/log/test.log",
                    "backup_path": "/backup/test.log",
                    "status": "success"
                }])
            }
        }
        mock_get_client.return_value = mock_client
        
        response = self.client.get("/backup-file", {
            "host_id_list": "1",
            "search_path": "/var/log",
            "suffix": ".log",
            "backup_path": "/backup"
        })
        
        self.assertEqual(response.status_code, 200)
        data = response.json()
        self.assertTrue(data["result"])
        self.assertEqual(data["code"], WEB_SUCCESS_CODE)
        
        # 验证备份记录是否创建
        backup_records = BackupRecord.objects.filter(bk_host_id=1)
        self.assertTrue(backup_records.exists())

    @patch("home_application.views.get_client_by_request")
    def test_backup_file_job_failed(self, mock_get_client):
        """测试文件备份作业执行失败"""
        mock_client = MagicMock()
        mock_client.jobv3.execute_job_plan.return_value = {
            "data": {"job_instance_id": 12345}
        }
        mock_client.jobv3.get_job_instance_status.return_value = {
            "data": {
                "step_instance_list": [{"status": 3}]  # 失败状态
            }
        }
        mock_get_client.return_value = mock_client
        
        response = self.client.get("/backup-file", {
            "host_id_list": "1",
            "search_path": "/var/log",
            "suffix": ".log",
            "backup_path": "/backup"
        })
        
        self.assertEqual(response.status_code, 200)
        data = response.json()
        self.assertFalse(data["result"])
        self.assertEqual(data["message"], "backup failed")

    def test_backup_file_invalid_params(self):
        """测试文件备份参数无效"""
        response = self.client.get("/backup-file", {
            "host_id_list": "",
            "search_path": "",
            "suffix": "",
            "backup_path": ""
        })
        
        self.assertEqual(response.status_code, 200)
        # 应该返回错误信息


class BackupRecordApiTest(BaseTestCase):
    """备份记录API测试"""

    def test_get_backup_record_success(self):
        """测试获取备份记录成功"""
        response = self.client.get("/backup-record")
        
        self.assertEqual(response.status_code, 200)
        data = response.json()
        self.assertTrue(data["result"])
        self.assertEqual(data["code"], WEB_SUCCESS_CODE)
        self.assertIsInstance(data["data"], list)
        self.assertTrue(len(data["data"]) > 0)

    def test_backup_record_ordering(self):
        """测试备份记录排序"""
        # 创建更多备份记录
        BackupRecord.objects.create(
            bk_host_id=2,
            bk_file_dir="/var/log",
            bk_file_suffix=".log",
            bk_backup_name="test_backup_20231202.log",
            bk_file_create_time="2023-12-02 10:00:00",
            bk_file_operator="admin",
            bk_job_link="http://job.example.com/task/124"
        )
        
        response = self.client.get("/backup-record")
        data = response.json()
        
        # 验证按ID倒序排列
        records = data["data"]
        self.assertTrue(len(records) >= 2)
        self.assertGreater(records[0]["id"], records[1]["id"])


class ApiStatisticsTest(BaseTestCase):
    """API统计功能测试"""

    def test_api_request_count_model(self):
        """测试API请求次数模型"""
        # 测试创建
        api_count = ApiRequestCount.objects.create(
            api_category="test",
            api_name="test_api",
            request_count=5
        )
        self.assertEqual(api_count.api_category, "test")
        self.assertEqual(api_count.api_name, "test_api")
        self.assertEqual(api_count.request_count, 5)
        
        # 测试唯一约束
        with self.assertRaises(Exception):
            ApiRequestCount.objects.create(
                api_category="test",
                api_name="test_api",
                request_count=10
            )

    def test_api_request_count_str(self):
        """测试API请求次数模型的字符串表示"""
        api_count = ApiRequestCount.objects.get(api_category="host", api_name="get_hosts_list")
        self.assertEqual(str(api_count), "host-get_hosts_list")


class BusinessApiTest(BaseTestCase):
    """业务API测试"""

    @patch("home_application.views.get_client_by_request")
    def test_get_bizs_list_success(self, mock_get_client):
        """测试获取业务列表成功"""
        mock_client = MagicMock()
        mock_client.cc.search_business.return_value = {
            "result": True,
            "data": {
                "info": [
                    {"bk_biz_id": 1, "bk_biz_name": "测试业务"}
                ],
                "count": 1
            }
        }
        mock_get_client.return_value = mock_client
        
        response = self.client.get("/biz-list")
        
        self.assertEqual(response.status_code, 200)
        data = response.json()
        self.assertTrue(data["result"])
        self.assertEqual(data["data"]["count"], 1)


class SetApiTest(BaseTestCase):
    """集群API测试"""

    @patch("home_application.views.get_client_by_request")
    def test_get_sets_list_success(self, mock_get_client):
        """测试获取集群列表成功"""
        mock_client = MagicMock()
        mock_client.cc.search_set.return_value = {
            "result": True,
            "data": {
                "info": [
                    {"bk_set_id": 1, "bk_set_name": "测试集群", "bk_biz_id": 1}
                ],
                "count": 1
            }
        }
        mock_get_client.return_value = mock_client
        
        response = self.client.get("/set-list", {"bk_biz_id": 1})
        
        self.assertEqual(response.status_code, 200)
        data = response.json()
        self.assertTrue(data["result"])


class ModuleApiTest(BaseTestCase):
    """模块API测试"""

    @patch("home_application.views.get_client_by_request")
    def test_get_modules_list_success(self, mock_get_client):
        """测试获取模块列表成功"""
        mock_client = MagicMock()
        mock_client.cc.search_module.return_value = {
            "result": True,
            "data": {
                "info": [
                    {"bk_module_id": 1, "bk_module_name": "测试模块", "bk_set_id": 1, "bk_biz_id": 1}
                ],
                "count": 1
            }
        }
        mock_get_client.return_value = mock_client
        
        response = self.client.get("/module-list", {
            "bk_biz_id": 1,
            "bk_set_id": 1
        })
        
        self.assertEqual(response.status_code, 200)
        data = response.json()
        self.assertTrue(data["result"])


class HostDetailApiTest(BaseTestCase):
    """主机详情API测试"""

    @patch("home_application.views.get_client_by_request")
    def test_get_host_detail_success(self, mock_get_client):
        """测试获取主机详情成功"""
        mock_client = MagicMock()
        mock_client.cc.get_host_base_info.return_value = {
            "result": True,
            "data": {
                "bk_host_id": 1,
                "bk_host_innerip": "127.0.0.1",
                "bk_os_type": "Linux"
            }
        }
        mock_get_client.return_value = mock_client
        
        response = self.client.get("/host-detail", {"bk_host_id": 1})
        
        self.assertEqual(response.status_code, 200)
        data = response.json()
        self.assertTrue(data["result"])


class ModelTest(BaseTestCase):
    """模型测试"""

    def test_business_model(self):
        """测试业务模型"""
        self.assertEqual(str(self.business), "测试业务(1)")
        self.assertEqual(self.business.bk_biz_name, "测试业务")
        self.assertEqual(self.business.bk_biz_id, 1)

    def test_set_model(self):
        """测试集群模型"""
        self.assertEqual(str(self.set), "测试集群(1)")
        self.assertEqual(self.set.bk_set_name, "测试集群")
        self.assertEqual(self.set.bk_biz_id, self.business)

    def test_module_model(self):
        """测试模块模型"""
        self.assertEqual(str(self.module), "测试模块(1)")
        self.assertEqual(self.module.bk_module_name, "测试模块")
        self.assertEqual(self.module.bk_set_id, self.set)

    def test_host_model(self):
        """测试主机模型"""
        self.assertEqual(str(self.host), "127.0.0.1(1)")
        self.assertEqual(self.host.bk_host_innerip, "127.0.0.1")
        self.assertEqual(self.host.bk_biz_id, self.business)

    def test_host_detail_model(self):
        """测试主机详情模型"""
        self.assertEqual(str(self.host_detail), "127.0.0.1的详细信息")
        self.assertEqual(self.host_detail.host, self.host)
        self.assertEqual(self.host_detail.cpu, "Intel(R) Core(TM) i7-8700K")

    def test_backup_record_model(self):
        """测试备份记录模型"""
        self.assertEqual(self.backup_record.bk_host_id, 1)
        self.assertEqual(self.backup_record.bk_file_dir, "/var/log")
        self.assertEqual(self.backup_record.bk_file_suffix, ".log")


class ExceptionHandlingTest(BaseTestCase):
    """异常处理测试"""

    @patch("home_application.views.get_client_by_request")
    def test_host_list_exception(self, mock_get_client):
        """测试主机列表异常处理"""
        mock_get_client.side_effect = Exception("Connection error")
        
        response = self.client.get("/host-list", {"bk_biz_id": 1})
        
        self.assertEqual(response.status_code, 200)
        data = response.json()
        self.assertEqual(data["code"], 1)
        self.assertIn("服务器异常", data["message"])

    @patch("home_application.views.get_client_by_request")
    def test_search_file_exception(self, mock_get_client):
        """测试文件搜索异常处理"""
        mock_get_client.side_effect = Exception("Job service error")
        
        response = self.client.get("/search-file", {
            "host_id_list": "1",
            "search_path": "/var/log",
            "suffix": ".log"
        })
        
        self.assertEqual(response.status_code, 200)
        # 应该返回错误信息

    @patch("home_application.views.get_client_by_request")
    def test_backup_file_exception(self, mock_get_client):
        """测试文件备份异常处理"""
        mock_get_client.side_effect = Exception("Backup service error")
        
        response = self.client.get("/backup-file", {
            "host_id_list": "1",
            "search_path": "/var/log",
            "suffix": ".log",
            "backup_path": "/backup"
        })
        
        self.assertEqual(response.status_code, 200)
        # 应该返回错误信息


class IntegrationTest(BaseTestCase):
    """集成测试"""

    def test_complete_workflow(self):
        """测试完整的工作流程"""
        # 1. 获取业务列表
        with patch("home_application.views.get_client_by_request") as mock_get_client:
            mock_client = MagicMock()
            mock_client.cc.search_business.return_value = {
                "result": True,
                "data": {"info": [{"bk_biz_id": 1, "bk_biz_name": "测试业务"}], "count": 1}
            }
            mock_get_client.return_value = mock_client
            
            response = self.client.get("/biz-list")
            self.assertEqual(response.status_code, 200)
        
        # 2. 获取主机列表
        with patch("home_application.views.get_client_by_request") as mock_get_client:
            mock_client = MagicMock()
            mock_client.cc.list_biz_hosts.return_value = {
                "result": True,
                "data": {"info": [{"bk_host_id": 1, "bk_host_innerip": "127.0.0.1"}], "count": 1}
            }
            mock_get_client.return_value = mock_client
            
            response = self.client.get("/host-list", {"bk_biz_id": 1})
            self.assertEqual(response.status_code, 200)
        
        # 3. 获取备份记录
        response = self.client.get("/backup-record")
        self.assertEqual(response.status_code, 200)
        data = response.json()
        self.assertTrue(data["result"])
